﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using static Enums.Timer;

/// <summary>
/// UGUI Text 类扩展
/// </summary>
public static class TextExtension
{

    private static readonly Vector3 m_GrayFactor = new Vector3(0.22f, 0.707f, 0.071f);

    private static readonly Dictionary<int, Color> m_TxtColorDic = new Dictionary<int, Color>();

    public static void SetGray(this Text text, bool isGray)
    {
        if (isGray)
        {
            if (m_TxtColorDic.TryGetValue(text.GetInstanceID(), out var color))
            {
                if (color != text.color)
                {
                    return;
                }
            }

            m_TxtColorDic[text.GetInstanceID()] = text.color;
            float gray = Vector3.Dot(new Vector3(text.color.r, text.color.g, text.color.b), m_GrayFactor);
            text.color = new Color(gray, gray, gray, text.color.a);
        }
        else if (!isGray && m_TxtColorDic.TryGetValue(text.GetInstanceID(), out var color))
        {
            text.color = color;
        }

       //TODO:设置描边置灰
    }

    /// <summary>
    /// 设置本地化语言
    /// </summary>
    /// <param name="text"></param>
    /// <param name="id">本地化 id</param>
    public static void SetLocalize(this Text text, string key)
    {
        text.text = key.FormatLocalize();
    }
    /// <summary>
    /// 设置本地化语言  如果 key == null 会 Deactive text.gameObject
    /// </summary>
    /// <param name="text"></param>
    /// <param name="id">本地化 id</param>
    public static void SetLocalizeAndActive(this Text text, string key)
    {
        if (key == null)
            text.SetActive(false);
        else
        {
            text.SetActive(true);
            text.text = key.FormatLocalize();
        }
    }

    /// <summary>
    /// 设置本地化语言
    /// </summary>
    /// <param name="text"></param>
    /// <param name="key">本地化 id</param>
    /// <param name="args">参数</param>
    public static void SetLocalize(this Text text, string key, params object[] args)
    {
        text.text = key.FormatLocalize(args);
    }

    /// <summary>
    /// 设置是否足够的文本颜色
    /// </summary>
    /// <param name="text"></param>
    /// <param name="isEnought">是否足够</param>
    /// <param name="enoughtColor">足够时显示的颜色</param>
    /// <param name="disEnoughtColor">不足够时显示的颜色</param>
    public static void SetEnought(this Text text,bool isEnought, string enoughtColor = Constant.Color.ENOUGH_GREEN, string disEnoughtColor = Constant.Color.DEFICIENCY_RED)
    {
        text.SetColor(isEnought ? enoughtColor : disEnoughtColor);
    }

    /// <summary>
    /// 设置文本颜色
    /// </summary>
    /// <param name="text"></param>
    /// <param name="colorHtml">文字颜色 Html 码</param>
    public static void SetColor(this Text text, string colorHtml)
    {
        if (!colorHtml.Contains("#"))
        {
            colorHtml = "#" + colorHtml;
        }
        if (ColorUtility.TryParseHtmlString(colorHtml, out Color color))
        {
            m_TxtColorDic[text.GetInstanceID()] = text.color;
            text.color = color;
        }
    }


    /// <summary>
    /// 设置文本颜色
    /// </summary>
    /// <param name="text"></param>
    /// <param name="color">文字颜色</param>
    public static void SetColor(this Text text, Color color)
    {
        m_TxtColorDic[text.GetInstanceID()] = text.color;
        text.color = color;
    }

    /// <summary>
    /// 设置透明度
    /// </summary>
    /// <param name="img"></param>
    /// <param name="alpha"></param>
    public static void SetAlpha(this Text text, float alpha)
    {
        Color color = text.color;
        color.a = alpha;
        text.color = color;
    }

    /// <summary>
    /// 设置富文本
    /// </summary>
    /// <param name="text"></param>
    /// <param name="content">内容</param>
    /// <param name="size">字体大小</param>
    /// <param name="color">文字颜色</param>
    public static void RichText(this Text text, string content, int size, string color)
    {
        text.text = Utility.RichText.Formt(content, size, color);
    }

    /// <summary>
    /// 获取文本长度
    /// </summary>
    public static float GetTextWidth(this Text text)
    {
        return text.GetTextWidth(text.text);
    }

    public static float GetTextWidth(this Text text, string str)
    {
        Font font = text.font;
        int fontsize = text.fontSize;
        font.RequestCharactersInTexture(str, fontsize, FontStyle.Normal);

        float width = 0f;
        for (int i = 0; i < str.Length; i++)
        {
            if (font.GetCharacterInfo(str[i], out CharacterInfo characterInfo, fontsize))
                width += characterInfo.advance;
        }
        return width;
    }

    public static void FixedWidth(this Text text)
    {
        float width = text.GetTextWidth();
        text.rectTransform.sizeDelta = new Vector2(width, text.rectTransform.sizeDelta.y);
    }

 

    /// <summary>
    /// 通用的倒计时方法
    /// </summary>
    /// <param name="comp">文本组件</param>
    /// <param name="state">是否播放</param>
    /// <param name="endTime">活动结束时间</param>
    /// <param name="timeFormat">倒计时文本</param>
    /// <param name="timeFormatType">时间格式类型</param>
    /// <param name="timeShowCount">时间格式显示位数</param>
    /// <param name="timeFormatLanguageType">时间格式语言枚举</param>
    /// <param name="callback">结束回调</param>
    /// <param name="defalutI18n">默认显示文本</param>
    public static void CountDownTime(this Text comp, bool state, long endTime = 0, string timeFormat = "", TimeFormatType timeFormatType = TimeFormatType.DD_TO_SS_ALL, TimeShowCount timeShowCount = TimeShowCount.All, TimeFormatLanguageType timeFormatLanguageType = TimeFormatLanguageType.I18n, Action callback = null,string defalutI18n="")
    {
        if (comp == null)
        {
            return;
        }

        if (!comp.gameObject.activeInHierarchy)
        {
            return;
        }

        if (!state)
        {
            comp.StopAllCoroutines();
            if (!defalutI18n.IsNullOrEmpty())
            {
                comp.SetLocalize(defalutI18n);
            }
            return;
        }
        comp.StopAllCoroutines();
        long serverTime = 0;
        long lessTime = endTime - serverTime;
        if (lessTime > 0)
        {
            comp.CountDownTimeFormat(endTime, timeFormat.FormatLocalize(), () =>
            {
                callback?.Invoke();
                if (!defalutI18n.IsNullOrEmpty())
                {
                    comp.SetLocalize(defalutI18n);
                }
            }, timeFormatType, timeShowCount, timeFormatLanguageType);
        }
        else
        {
            if (!defalutI18n.IsNullOrEmpty())
            {
                comp.SetLocalize(defalutI18n);
            }
            else
            {
                comp.SetLocalize(timeFormat, 0.TimeToString(timeFormatType, timeShowCount, timeFormatLanguageType));
            }   
        }
    }


    /// <summary>
    /// 倒计时（帧）
    /// </summary>
    /// <param name="text"></param>
    /// <param name="time">总时间</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <param name="type">时间格式类型</param>
    /// <param name="count">展示位数</param>
    /// <param name="languageType">语言类型</param>
    /// <returns></returns>
    public static Coroutine CountDownTime(this Text text, float time, Action completeCallback = null, TimeFormatType type = TimeFormatType.HH_MM_SS, TimeShowCount count = TimeShowCount.All, TimeFormatLanguageType languageType = TimeFormatLanguageType.Default)
    {
        return text.StartCoroutine(Utility.Coroutine.CountDown(time,
            (leftTime) => text.text = leftTime.TimeToString(type, count, languageType),
            completeCallback));
    }

    /// <summary>
    /// 倒计时（帧）
    /// </summary>
    /// <param name="text"></param>
    /// <param name="time">总时间</param>
    /// <param name="format">字符串格式</param>
    /// <param name="type">显示单位数量</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <param name="type">时间格式类型</param>
    /// <param name="count">展示位数</param>
    /// <param name="languageType">语言类型</param>
    /// <returns></returns>
    public static Coroutine CountDownTimeFormat(this Text text, float time, string format = "{0}", Action completeCallback = null, TimeFormatType type = TimeFormatType.HH_MM_SS, TimeShowCount count = TimeShowCount.All, TimeFormatLanguageType languageType = TimeFormatLanguageType.Default)
    {
        return text.StartCoroutine(Utility.Coroutine.CountDown(time,
                                           (leftTime) => text.text = format.Format(leftTime.TimeToString(type, count, languageType)),
                                           completeCallback));
    }


    /// <summary>
    /// 倒计时（帧）
    /// </summary>
    /// <param name="text"></param>
    /// <param name="time">总时间</param>
    /// <param name="format">字符串格式</param>
    /// <param name="type">显示单位数量</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <param name="type">时间格式类型</param>
    /// <param name="count">展示位数</param>
    /// <param name="languageType">语言类型</param>
    /// <returns></returns>
    public static Coroutine CountDownTimeFormat(this Text text, int time, string format = "{0}", Action completeCallback = null, TimeFormatType type = TimeFormatType.HH_MM_SS, TimeShowCount count = TimeShowCount.All, TimeFormatLanguageType languageType = TimeFormatLanguageType.Default)
    {
        return text.StartCoroutine(Utility.Coroutine.CountDown(time,
            (leftTime) => text.text = format.Format(leftTime.TimeToString(type, count, languageType)),
            completeCallback));
    }

    /// <summary>
    /// 倒计时
    /// </summary>
    /// <param name="text"></param>
    /// <param name="timeStamp">结束时间戳（毫秒）</param>
    /// <param name="format">字符串格式，默认整数格式</param>
    /// <param name="completeCallback">回调函数</param>
    /// <param name="type">时间格式类型</param>
    /// <param name="count">展示位数</param>
    /// <param name="languageType">语言类型</param>
    /// <returns></returns>
    public static Coroutine CountDownTimeFormat(this Text text, long timeStamp, string format = "{0}", Action completeCallback = null, TimeFormatType type = TimeFormatType.HH_MM_SS, TimeShowCount count = TimeShowCount.All, TimeFormatLanguageType languageType = TimeFormatLanguageType.Default)
    {
        long serverTime = 0;
        float lastTime = (timeStamp - serverTime) / 1000;
        return text.CountDownTimeFormat(lastTime, format, completeCallback, type, count, languageType);
    }

    /// <summary>
    /// 倒计时（帧）
    /// </summary>
    /// <param name="text"></param>
    /// <param name="time">总时间</param>
    /// <param name="format">字符串格式，默认整数格式</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <returns></returns>
    public static Coroutine CountDown(this Text text, float time, string format = Constant.Format.INTEGER_STRING_FORMAT, Action completeCallback = null)
    {
        return text.StartCoroutine(Utility.Coroutine.CountDown(time,
            (leftTime) => text.text = leftTime.ToString(format),
            completeCallback));
    }

    /// <summary>
    /// TimeSpan 倒计时
    /// </summary>
    /// <param name="text"></param>
    /// <param name="timeSpan">时间间隔</param>
    /// <param name="format">字符串格式</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <returns></returns>
    public static Coroutine CountDown(this Text text, TimeSpan timeSpan, string format = Constant.Format.HH_MM_SS_TIME_FORMAT, Action completeCallback = null)
    {
        return text.StartCoroutine(Utility.Coroutine.Timer((float)timeSpan.TotalSeconds,
            (timer) => text.text = timeSpan.Add(TimeSpan.FromSeconds(-timer)).ToString(format)
            , completeCallback));
    }

    /// <summary>
    /// 倒计时
    /// </summary>
    /// <param name="text"></param>
    /// <param name="time">总时间</param>
    /// <param name="format">字符串格式，默认整数格式</param>
    /// <param name="content">格式化文本</param>
    /// <returns></returns>
    public static Coroutine CountDownFormat(this Text text, float time, string content, string format = Constant.Format.INTEGER_STRING_FORMAT, Action completeCallback = null)
    {
        return text.StartCoroutine(Utility.Coroutine.CountDown(time, (leftTime) =>
        {
            string leftTimeStr = leftTime.ToString(format);
            text.text = content.IsNullOrEmpty()
                ? leftTimeStr
                : string.Format(content, leftTimeStr);
        }, completeCallback));
    }



    /// <summary>
    /// TimeSpan 倒计时（格式化文本）
    /// </summary>
    /// <param name="text"></param>
    /// <param name="timeSpan">时间间隔</param>
    /// <param name="content">格式化文本</param>
    /// <param name="format">字符串格式</param>
    /// <param name="completeCallback">倒计时结束回调</param>
    /// <returns></returns>
    public static Coroutine CountDownFormat(this Text text, TimeSpan timeSpan, string content, string format = Constant.Format.HH_MM_SS_TIME_FORMAT, Action completeCallback = null)
    {
        return text.StartCoroutine(Utility.Coroutine.Timer((float)timeSpan.TotalSeconds, (timer) =>
        {
            string leftTimeStr = timeSpan.Add(TimeSpan.FromSeconds(-timer)).ToString(format);
            text.text = content.IsNullOrEmpty()
                ? leftTimeStr
                : string.Format(content, leftTimeStr);
        }, completeCallback));
    }


    public static Coroutine AddTimeFormat(this Text text,long startTime,  float totalTime = -1, string format = "{0}", Action completeCallback = null, TimeFormatType type = TimeFormatType.DD_TO_SS_ALL, TimeShowCount count = TimeShowCount.All, TimeFormatLanguageType languageType = TimeFormatLanguageType.Default)
    {
        return text.StartCoroutine(Utility.Coroutine.CountAdd(startTime, totalTime,
                                           (leftTime) => text.text = format.Format(leftTime.TimeToString(type, count, languageType)),
                                           completeCallback));
    }
}
